package ait.mediabroadcast;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.seamless.android.FixedAndroidLogHandler;
import org.seamless.util.logging.LoggingUtil;
import org.teleal.cling.android.AndroidUpnpService;
import org.teleal.cling.controlpoint.ActionCallback;
import org.teleal.cling.model.action.ActionArgumentValue;
import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.message.UpnpResponse;
import org.teleal.cling.model.meta.Action;
import org.teleal.cling.model.meta.ActionArgument;
import org.teleal.cling.model.meta.Device;
import org.teleal.cling.model.meta.LocalDevice;
import org.teleal.cling.model.meta.LocalService;
import org.teleal.cling.model.meta.RemoteDevice;
import org.teleal.cling.model.meta.Service;
import org.teleal.cling.model.types.UDAServiceType;
import org.teleal.cling.registry.DefaultRegistryListener;
import org.teleal.cling.registry.Registry;
import org.teleal.cling.support.model.BrowseFlag;
import org.teleal.cling.support.model.DIDLObject;
import org.teleal.cling.support.model.PersonWithRole;
import org.teleal.cling.support.model.Res;
import org.teleal.cling.support.model.WriteStatus;
import org.teleal.cling.support.model.container.Container;
import org.teleal.cling.support.model.item.Item;
import org.teleal.cling.support.model.item.MusicTrack;
import org.teleal.cling.support.model.item.VideoItem;
import org.teleal.common.util.MimeType;

import ait.mediabroadcast.helper.DeviceRole;
import ait.mediabroadcast.helper.MyConstants;
import ait.mediabroadcast.helper.PlaybackStatus;
import ait.mediabroadcast.helper.UpnpServiceManager;
import ait.mediabroadcast.listitem.ContentItem;
import ait.mediabroadcast.listitem.DeviceItem;
import ait.mediabroadcast.mediaserver.AndroidContentBrowseActionCallback;
import ait.mediabroadcast.mediaserver.AndroidContentNode;
import ait.mediabroadcast.mediaserver.AndroidContentTree;
import ait.mediabroadcast.mediaserver.MediaServer;
import ait.mediabroadcast.pauseresume.PauseResumeService;
import ait.mediabroadcast.pauseresume.PauseResumeSubscriptionCallback;
import ait.mediabroadcast.pauseresume.SetActionInvocation;
import ait.mediabroadcast.player.MyPlayer;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
	
	private static final Logger log = Logger.getLogger(MainActivity.class.toString());
	private static final String LOGTAG = MainActivity.class.toString();
	
	private ListView deviceListView;
	private ListView contentListView;
	
	private ArrayAdapter<DeviceItem> deviceListAdapter;
	private ArrayAdapter<ContentItem> contentListAdapter;

	private BrowseRegistryListener deviceRegistryListener = new BrowseRegistryListener();
	private AndroidUpnpService upnpService;
	private MediaServer mediaServer;
	
	private Handler mHandler;
	
	private boolean serverPrepared;
	
	private int browsedDevice = -1;
	private LocalDevice mLocalDevice;
	
	private Activity mActivity;

// ->V
	ProgressDialog progressBar;
	private int progressBarStatus = 0;
	private Handler progressBarHandler = new Handler();
// <-V

	private ServiceConnection serviceConnection = new ServiceConnection() {

		public void onServiceConnected(ComponentName className, IBinder service) {
			upnpService = UpnpServiceManager.getInstance(service);
			
			Log.v(LOGTAG, "Connected to UPnP Service");
 			
			// Clear the list
			deviceListAdapter.clear();
						
			if (mediaServer == null) {
				new CreateMediaServerTask().execute("");
			}
						
			// Now add all devices to the list we already know about
			for (Device device : upnpService.getRegistry().getDevices()) {
				deviceRegistryListener.deviceAdded(new DeviceItem(device));
			}

			// Get ready for future device advertisements
 			upnpService.getRegistry().addListener(deviceRegistryListener);
			
			// Search asynchronously for all devices, they will respond soon
			upnpService.getControlPoint().search();
		}

		public void onServiceDisconnected(ComponentName className) {
			Log.d(LOGTAG, "onServiceDisconnected");
			upnpService = null;
		}
	};
	
	private class CreateMediaServerTask extends AsyncTask<String, Void, Void> {

		@Override
		protected Void doInBackground(String... params) {
			try {
				InetAddress localAddress = getLocalIpAddress();
				mediaServer = new MediaServer(localAddress);
				mLocalDevice = mediaServer.getLocalDevice();
				Registry registry = upnpService.getRegistry();
				registry.addDevice(mLocalDevice);
				Log.v(LOGTAG, mLocalDevice.getDisplayString());
			} catch (Exception e) {
				Log.e(LOGTAG, e.getMessage(), e);
				e.printStackTrace();
			}
			return null;
		}
		
		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);

// ->V
			// prepare for a progress bar dialog
			
			progressBar = new ProgressDialog(MainActivity.this);
			progressBar.setCancelable(true);
			progressBar.setMessage("Scanning ...");
//			progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER );
			progressBar.setProgress(0);
			progressBar.setMax(100);
			progressBar.show();
			
/*			//reset progress bar status
			progressBarStatus = 50;

			// Update the progress bar
			progressBarHandler.post(new Runnable() {
				public void run() {
				  progressBar.setProgress(progressBarStatus);
				}
			});
*/			
// <-V
			
			prepareMediaServer();

// ->V
			// close the progress bar dialog
			progressBar.dismiss();
// <-V
			
		}
		
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {

 		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);
		deviceListView = (ListView) findViewById(R.id.deviceListView);
		contentListView = (ListView) findViewById(R.id.contentListView);
		
		deviceListAdapter = new ArrayAdapter<DeviceItem>(this, android.R.layout.simple_list_item_1);
		if (deviceListView != null) {
			if (deviceListAdapter!= null)
				deviceListView.setAdapter(deviceListAdapter);
			deviceListView.setOnItemClickListener(deviceItemListener);
		}
		contentListAdapter = new ArrayAdapter<ContentItem>(this, android.R.layout.simple_list_item_1);
		contentListView.setAdapter(contentListAdapter);
		contentListView.setOnItemClickListener(contentItemListener);

		mActivity = (Activity) this;
		Intent intent = new Intent(this, IlMioAndroidUpnpService.class);
		
		try {
			// This will start the UPnP service if it wasn't already started
			getApplicationContext().bindService(
					intent, serviceConnection,	
					Context.BIND_AUTO_CREATE
					);
		} catch (SecurityException se) {
			Log.e(LOGTAG, se.getMessage(), se);
		} catch (Exception e) {
			Log.e(LOGTAG, e.getMessage(), e);
		}
		
		mHandler = new Handler(Looper.getMainLooper()) {
			@Override
	        public void handleMessage(Message inputMessage) {
	            // Gets the folders (containers) and files (items) from the incoming Message object.
				if (inputMessage.what == MyConstants.GET_CONTENT_DIR_COMPLETED) {
					Object [] didlObjects = (Object []) inputMessage.obj;
					List<Container> containers = (List<Container>) didlObjects[0];
					List<Item> items = (List<Item>) didlObjects[1];
					Service service = (Service) didlObjects[2];
					
					// change the values of the contents
					contentListAdapter.clear();
					for (Container c : containers) {
						contentListAdapter.add(new ContentItem(c, service));
					}
					
					for (Item i : items) {
						contentListAdapter.add(new ContentItem(i, service));
					}					
				} else if (inputMessage.what == MyConstants.RECEIVED_BROADCAST) {
					Object [] values = (Object []) inputMessage.obj;
					String playbackValues = values[0].toString();
					String serverValues = values[1].toString();
					final String [] playbackTokens = playbackValues.split(MyConstants.DELIMITER);
					final String [] serverTokens = serverValues.split(MyConstants.DELIMITER);
					
					// if server empty, then it's only an offer to broadcast. don't play media now!
					// check the pause, to see if 
					if (PlaybackStatus.getServer().isEmpty()) {

						if (!playbackTokens[0].equals(MyConstants.PAUSE_STRING)) {
							if (serverTokens.length == 2) {
								// show dialog to ask user if they want to connect
								AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mActivity);
								alertDialogBuilder.setMessage(getString(R.string.receive_broadcast_message) + " " + serverTokens[1] + "?")
								.setTitle(getString(R.string.receive_broadcast_title));
								alertDialogBuilder.setNegativeButton(getString(R.string.no), new OnClickListener() {

									@Override
									public void onClick(DialogInterface dialog, int which) {
										// Do nothing!
										dialog.cancel();
									}
								});
								alertDialogBuilder.setPositiveButton(getString(R.string.yes), new OnClickListener() {

									@Override
									public void onClick(DialogInterface dialog, int which) {
										setBroadcastServer(serverTokens[0], DeviceRole.CLIENT_DEVICE);
									}
								});
								AlertDialog alertDialog = alertDialogBuilder.create();
								alertDialog.show();
							}
						}
					} else {
						setPlayMedia(playbackTokens, serverTokens);
					}
				}
	        }
		};
		
		setLogging();
	}
	
	private void setPlayMedia(String [] playbackTokens, String [] serverTokens) {
		if (playbackTokens.length > 1) {
			
			/* if the server who sent the data is the same server of our device
			 * play/pause the media, otherwise do nothing
			 */
			Log.d(LOGTAG, "server: " + PlaybackStatus.getServer());
			if (PlaybackStatus.getServer().equals(serverTokens[0])) {

				String playOrPause = "", playUri = "", timePoint = "", mediaTitle = "";
				
				if (playbackTokens.length == 4) {
					playOrPause = playbackTokens[0];
					playUri = playbackTokens[1];
					timePoint = playbackTokens[2];
					mediaTitle = playbackTokens[3];
				}
				
				if (playOrPause.equals(MyConstants.PLAY_STRING)) {
					startPlayer(playUri, mediaTitle, timePoint, MyConstants.PLAY_STRING, true);
				} else { // if PAUSE message
					
					// reset server status
					PlaybackStatus.resetBroadcastServer();
					
					// pause media playing
					Intent pauseIntent = new Intent(MainActivity.this, MyPlayer.class);
					pauseIntent.setAction(MyConstants.PAUSE_STRING);
					startActivity(pauseIntent);
				}
			}
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (upnpService != null) {
			upnpService.getRegistry().removeListener(deviceRegistryListener);
			AndroidContentTree.clearTree();
		}
		// This will stop the UPnP service if nobody else is bound to it
		try {
			getApplicationContext().unbindService(serviceConnection);
		} catch (Exception e) {
			Log.e(LOGTAG, "error unbind service: " + e.getMessage());
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, 0, 0, getString(R.string.search_devices));
		menu.add(0, 1, 0, getString(R.string.reset_bc_server));
		return true;
	}
	
	OnItemClickListener deviceItemListener = new OnItemClickListener() {

		protected Container createRootContainer(Service service) {
			Container rootContainer = new Container();
			rootContainer.setId("0");
			rootContainer.setTitle("Content Directory on "
					+ service.getDevice().getDisplayString());
			return rootContainer;
		}
		
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			
			Device device = deviceListAdapter.getItem(position).getDevice();
			browsedDevice = position;
			Service service = device.findService(new UDAServiceType(MyConstants.CONTENT_DIRECTORY));
			if (service == null) {
				Toast.makeText(MainActivity.this, "Cannot browse content in the device", Toast.LENGTH_SHORT);
				Log.e(LOGTAG, "ContentDirectory null");
			} else {
				Container rootContainer = createRootContainer(service);
				upnpService.getControlPoint().execute(
						new AndroidContentBrowseActionCallback(service, rootContainer, 
								BrowseFlag.DIRECT_CHILDREN, mHandler));
			}
		}
	};
	
	OnItemClickListener contentItemListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			final ContentItem selectedContent = contentListAdapter.getItem(position);
			if (selectedContent.isContainer()) {
				upnpService.getControlPoint().execute(
						new AndroidContentBrowseActionCallback(selectedContent.getService(), 
								selectedContent.getContainer(), BrowseFlag.DIRECT_CHILDREN, mHandler));
			} else {
				
				/*
				 *  before playing, let's send an update to subscribing device 
				 *  telling that we want to play (= be a server)
				 *  set some delay to send notification to other devices
				 */
				sendBroadcastRequest();
				setBroadcastServer(mLocalDevice.getIdentity().getUdn().toString(), DeviceRole.SERVER_DEVICE);
				
				progressBar = new ProgressDialog(MainActivity.this);
				progressBar.setTitle(getString(R.string.progress_bar_bc_title));
				progressBar.setMessage(getString(R.string.progress_bar_bc_message));
				progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER );
				progressBar.setProgress(0);
				progressBar.setCancelable(false);
				progressBar.show();
				
				final Handler delayHandler = new Handler();
				delayHandler.postDelayed(new Runnable() {
					
					@Override
					public void run() {
						
						/*
						 * then start playing after the delay is over
						 * we also have to notify that we are playing the media now
						 */
						progressBar.dismiss();
						String playUri = selectedContent.getItem().getFirstResource().getValue();
						String mediaTitle = selectedContent.getItem().getTitle();
						sendBroadcastMediaInfo(playUri, mediaTitle);
						
						startPlayer(playUri, mediaTitle, null, MyConstants.PLAY_STRING, false);
					}
					
				}, MyConstants.WAITING_BROADCAST_TIME);
			}
		}
		
	};

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		switch (item.getItemId()) {
			case 0:
				searchNetwork();
				break;
			case 1:
				PlaybackStatus.resetBroadcastServer();
				break;
		}
		return false;
	}
	
	private void searchNetwork() {
		if (upnpService == null)
			return;
		Toast.makeText(this, getString(R.string.search_devices), Toast.LENGTH_SHORT).show();
		upnpService.getRegistry().removeAllRemoteDevices();
		upnpService.getControlPoint().search();
	}

	protected class BrowseRegistryListener extends DefaultRegistryListener {

		/* Discovery performance optimization for very slow Android devices! */
		@Override
		public void remoteDeviceDiscoveryStarted(Registry registry, RemoteDevice device) {
			Log.d(LOGTAG, "Found device: " + device.getDetails().getFriendlyName());
		}

		@Override
		public void remoteDeviceDiscoveryFailed(Registry registry, final RemoteDevice device, final Exception ex) {
			Log.d(LOGTAG, "Failed discovering device: " + device.getDisplayString());
			runOnUiThread(new Runnable() {
				public void run() {
					Toast.makeText(
							MainActivity.this,
							"Discovery failed of '" + device.getDisplayString() + "': "
									+ (ex != null ? ex.toString() : "Couldn't retrieve device/service descriptors"),
									Toast.LENGTH_LONG
							).show();
				}
			});
		}
		/* End of optimization, you can remove the whole block if your Android handset is fast (>= 600 Mhz) */

		@Override
		public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
			if (checkDeviceServices(device)) {
				DeviceItem deviceItem = new DeviceItem(device);
				deviceAdded(deviceItem);
				startSubscribing(device);
			}
		}

		@Override
		public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
			deviceRemoved(new DeviceItem(device));
		}

		@Override
		public void localDeviceAdded(Registry registry, LocalDevice device) {
			if (checkDeviceServices(device)) {
				DeviceItem deviceItem = new DeviceItem(device);
				deviceAdded(deviceItem);
			}
		}

		@Override
		public void localDeviceRemoved(Registry registry, LocalDevice device) {
			deviceRemoved(new DeviceItem(device));
		}
		
		public void deviceAdded(final DeviceItem d) {
			runOnUiThread(new Runnable() {

				@Override
				public void run() {
					Log.d(LOGTAG, "deviceAdded: " + d.getDevice().getDetails().getFriendlyName());
					int position = deviceListAdapter.getPosition(d);
					if (position >= 0) {
						deviceListAdapter.remove(d);
						deviceListAdapter.insert(d, position);
					} else {
						deviceListAdapter.add(d);
					}
				}
				
			});
		}

		public void deviceRemoved(final DeviceItem di) {
			runOnUiThread(new Runnable() {
				public void run() {
					int pos = deviceListAdapter.getPosition(di);
					if (pos == browsedDevice) {
						contentListAdapter.clear();
					}
					deviceListAdapter.remove(di);
					browsedDevice = -1;
				}
			});
		}
	}
	
	private void prepareMediaServer() {

		if (serverPrepared)
			return;

		AndroidContentNode rootNode = AndroidContentTree.getRootNode();
		// Video Container
		Container videoContainer = new Container();
		videoContainer.setClazz(new DIDLObject.Class("object.container"));
		videoContainer.setId(AndroidContentTree.VIDEO_ID);
		videoContainer.setParentID(AndroidContentTree.ROOT_ID);
		videoContainer.setTitle("Videos");
		videoContainer.setRestricted(true);
		videoContainer.setWriteStatus(WriteStatus.NOT_WRITABLE);
		videoContainer.setChildCount(0);
		
		rootNode.getContainer().addContainer(videoContainer);
		rootNode.getContainer().setChildCount(
				rootNode.getContainer().getChildCount() + 1);
		AndroidContentTree.addNode(AndroidContentTree.VIDEO_ID, new AndroidContentNode(
				AndroidContentTree.VIDEO_ID, videoContainer));

		Cursor cursor;
		String[] videoColumns = { MediaStore.Video.Media._ID,
				MediaStore.Video.Media.TITLE, MediaStore.Video.Media.DATA,
				MediaStore.Video.Media.ARTIST,
				MediaStore.Video.Media.MIME_TYPE, MediaStore.Video.Media.SIZE,
				MediaStore.Video.Media.DURATION,
				MediaStore.Video.Media.RESOLUTION };
		
		CursorLoader cursorLoader = new CursorLoader(this,
				MediaStore.Video.Media.EXTERNAL_CONTENT_URI, videoColumns, null, null, null);
		cursor = cursorLoader.loadInBackground();
		if (cursor.moveToFirst()) {
			do {
				String id = AndroidContentTree.VIDEO_PREFIX
						+ cursor.getInt(cursor
								.getColumnIndex(MediaStore.Video.Media._ID));
				String title = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE));
				String creator = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Video.Media.ARTIST));
				String filePath = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
				String mimeType = cursor
						.getString(cursor
								.getColumnIndexOrThrow(MediaStore.Video.Media.MIME_TYPE));
				long size = cursor.getLong(cursor
						.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE));
				long duration = cursor
						.getLong(cursor
								.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));
				String resolution = cursor
						.getString(cursor
								.getColumnIndexOrThrow(MediaStore.Video.Media.RESOLUTION));
				Res res = new Res(new MimeType(mimeType.substring(0,
						mimeType.indexOf('/')), mimeType.substring(mimeType
						.indexOf('/') + 1)), size, "http://"
						+ mediaServer.getAddress() + "/" + id);
				res.setDuration(duration / (1000 * 60 * 60) + ":"
						+ (duration % (1000 * 60 * 60)) / (1000 * 60) + ":"
						+ (duration % (1000 * 60)) / 1000);
				res.setResolution(resolution);

				VideoItem videoItem = new VideoItem(id, AndroidContentTree.VIDEO_ID,
						title, creator, res);
				videoContainer.addItem(videoItem);
				videoContainer
						.setChildCount(videoContainer.getChildCount() + 1);
				AndroidContentTree.addNode(id,
						new AndroidContentNode(id, videoItem, filePath));

				Log.v(LOGTAG, "added video item " + title + "from " + filePath);
			} while (cursor.moveToNext());
		}

		// Audio Container
		Container audioContainer = new Container(AndroidContentTree.AUDIO_ID,
				AndroidContentTree.ROOT_ID, "Audios", "GNaP MediaServer",
				new DIDLObject.Class("object.container"), 0);
		audioContainer.setRestricted(true);
		audioContainer.setWriteStatus(WriteStatus.NOT_WRITABLE);
		rootNode.getContainer().addContainer(audioContainer);
		rootNode.getContainer().setChildCount(
				rootNode.getContainer().getChildCount() + 1);
		AndroidContentTree.addNode(AndroidContentTree.AUDIO_ID, new AndroidContentNode(
				AndroidContentTree.AUDIO_ID, audioContainer));

		String[] audioColumns = { MediaStore.Audio.Media._ID,
				MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
				MediaStore.Audio.Media.ARTIST,
				MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.SIZE,
				MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.ALBUM };
		cursorLoader = new CursorLoader(this,
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, audioColumns, null, null, null);
		cursor = cursorLoader.loadInBackground();
		if (cursor.moveToFirst()) {
			do {
				String id = AndroidContentTree.AUDIO_PREFIX
						+ cursor.getInt(cursor
								.getColumnIndex(MediaStore.Audio.Media._ID));
				String title = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
				String creator = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
				String filePath = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
				String mimeType = cursor
						.getString(cursor
								.getColumnIndexOrThrow(MediaStore.Audio.Media.MIME_TYPE));
				long size = cursor.getLong(cursor
						.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
				long duration = cursor
						.getLong(cursor
								.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
				String album = cursor.getString(cursor
						.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
				Res res = new Res(new MimeType(mimeType.substring(0,
						mimeType.indexOf('/')), mimeType.substring(mimeType
						.indexOf('/') + 1)), size, "http://"
						+ mediaServer.getAddress() + "/" + id);
				res.setDuration(duration / (1000 * 60 * 60) + ":"
						+ (duration % (1000 * 60 * 60)) / (1000 * 60) + ":"
						+ (duration % (1000 * 60)) / 1000);

				// Music Track must have `artist' with role field, or
				// DIDLParser().generate(didl) will throw nullpointException
				MusicTrack musicTrack = new MusicTrack(id,
						AndroidContentTree.AUDIO_ID, title, creator, album,
						new PersonWithRole(creator, "Performer"), res);
				audioContainer.addItem(musicTrack);
				audioContainer
						.setChildCount(audioContainer.getChildCount() + 1);
				AndroidContentTree.addNode(id, new AndroidContentNode(id, musicTrack,
						filePath));

				Log.v(LOGTAG, "added audio item " + title + "from " + filePath);
			} while (cursor.moveToNext());
		}
		
		cursor.close();
		serverPrepared = true;
	}
	
	private InetAddress getLocalIpAddress() throws UnknownHostException {
		WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
		WifiInfo wifiInfo = wifiManager.getConnectionInfo();
		int ipAddress = wifiInfo.getIpAddress();
		return InetAddress.getByName(String.format("%d.%d.%d.%d",
				(ipAddress & 0xff), (ipAddress >> 8 & 0xff),
				(ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff)));
	}
	
	private boolean checkDeviceServices(Device device) {
		Log.d(LOGTAG, device.getType().getNamespace() + " " + device.getType().getType());
		if (device.getType().getNamespace().equals("schemas-upnp-org") &&
				device.getType().getType().equals("MediaServer")) {
			return true;
		} else {
			return false;
		}
	}
	
	private void startSubscribing(Device device) {
		Service [] services = device.getServices();
		for (int i = 0; i < services.length; i++) {
			Log.d(LOGTAG, services[i].toString());
		}
		Service service = device.findService(new UDAServiceType(MyConstants.PAUSE_RESUME_SERVICE, 1));
		
		if (service != null) {
			PauseResumeSubscriptionCallback resumeSubscrCallback = 
					new PauseResumeSubscriptionCallback(service, mHandler);
			upnpService.getControlPoint().execute(resumeSubscrCallback);
		}
	}
	
	private void sendBroadcastRequest() {
		LocalService<PauseResumeService> prService = getLocalService();
		
		Action setServerAction = prService.getAction(MyConstants.ACTION_SET_SERVER);
		String newServerValue =  mLocalDevice.getIdentity().getUdn() + "::" +
				mLocalDevice.getDetails().getFriendlyName();
		
		ActionArgument argument = setServerAction.getInputArgument(MyConstants.ARGUMENT_NEW_SERVER);
		ActionArgumentValue aargv = new ActionArgumentValue(argument, newServerValue);
		ActionArgumentValue aargvArray [] = {aargv};
		SetActionInvocation actInvocation = new SetActionInvocation(setServerAction, aargvArray);

		ActionCallback setServerCallback = new ActionCallback(actInvocation) {
			
			@Override
			public void success(ActionInvocation invocation) {
				Log.d(LOGTAG, "success");
			}
			
			@Override
			public void failure(ActionInvocation invocation, UpnpResponse operation,
					String defaultMsg) {
				Log.e(LOGTAG, "failure");
			}
		};
		upnpService.getControlPoint().execute(setServerCallback);
	}
	
	private void setBroadcastServer(String serverUdn, DeviceRole role) {
		PlaybackStatus.setServer(serverUdn);
		PlaybackStatus.setCurrentRole(role);
	}
	
	private void sendBroadcastMediaInfo(String playUri, String mediaTitle) {
		LocalService<PauseResumeService> prService = getLocalService();
		Action action = prService.getAction(MyConstants.ACTION_SET_TARGET);
		String newTargetValue = MyConstants.PLAY_STRING + MyConstants.DELIMITER + playUri + MyConstants.DELIMITER + "0"
				+ MyConstants.DELIMITER + mediaTitle; 
		
		ActionArgument argument = action.getInputArgument(MyConstants.ARGUMENT_NEW_TARGET);
		ActionArgumentValue aargv = new ActionArgumentValue(argument, newTargetValue);
		ActionArgumentValue aargvArray [] = {aargv};
		SetActionInvocation actInvocation = new SetActionInvocation(action, aargvArray);

		ActionCallback callback = new ActionCallback(actInvocation) {
			
			@Override
			public void success(ActionInvocation invocation) {
				Log.d(LOGTAG, "success");
			}
			
			@Override
			public void failure(ActionInvocation invocation, UpnpResponse operation,
					String defaultMsg) {
				Log.e(LOGTAG, "failure");
			}
		};
		upnpService.getControlPoint().execute(callback);
	}
	
	private void startPlayer(String playUri, String mediaTitle, String pauseTime, String playOrPause,
			boolean isStreamed) {
		Intent intent = new Intent();
		intent.setClass(MainActivity.this, MyPlayer.class);
		intent.putExtra(MyConstants.PLAY_URI, playUri);
		intent.putExtra(MyConstants.MEDIA_TITLE, mediaTitle);
		intent.putExtra(MyConstants.PLAY_OR_PAUSE, playOrPause);
		if (pauseTime != null) {
			intent.putExtra(MyConstants.PAUSE_TIME, Integer.parseInt(pauseTime));
		}
		final Intent finalIntent = intent;
		Random rand = new Random();
	
		final Handler delayHandler = new Handler();
		delayHandler.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				
				startActivity(finalIntent);
			}
		}, (isStreamed? rand.nextInt(1000) + 100 : 0));
//		startActivity(intent);
	}
	
	private LocalService<PauseResumeService> getLocalService() {
		Service service = mLocalDevice.findService(new UDAServiceType(MyConstants.PAUSE_RESUME_SERVICE, 1));
		LocalService<PauseResumeService> prService = (LocalService<PauseResumeService>) service;
		return prService;
	}
	
	private void removeBroadcastServer() {
		PlaybackStatus.resetBroadcastServer();
		Toast toast = Toast.makeText(getApplicationContext(), 
				getString(R.string.reset_bc_server), Toast.LENGTH_SHORT);
		toast.show();
	}
	
	private void setLogging() {
		// Fix the logging integration between java.util.logging and Android internal logging
        LoggingUtil.resetRootHandler(new FixedAndroidLogHandler());
        Logger.getLogger("org.teleal.cling").setLevel(Level.FINE);

        // UDP communication
//        Logger.getLogger("org.teleal.cling.transport.spi.DatagramIO").setLevel(Level.FINE);
//        Logger.getLogger("org.teleal.cling.transport.spi.MulticastReceiver").setLevel(Level.FINE);

        // Discovery
        Logger.getLogger("org.teleal.cling.protocol.ProtocolFactory").setLevel(Level.FINER);
        Logger.getLogger("org.teleal.cling.protocol.async").setLevel(Level.FINER);

        // Description
        Logger.getLogger("org.teleal.cling.protocol.ProtocolFactory").setLevel(Level.FINER);
        Logger.getLogger("org.teleal.cling.protocol.RetrieveRemoteDescriptors").setLevel(Level.FINE);
        Logger.getLogger("org.teleal.cling.protocol.sync.ReceivingRetrieval").setLevel(Level.FINE);
        Logger.getLogger("org.teleal.cling.binding.xml.DeviceDescriptorBinder").setLevel(Level.FINE);
        Logger.getLogger("org.teleal.cling.binding.xml.ServiceDescriptorBinder").setLevel(Level.FINE);

        // Registry
        Logger.getLogger("org.teleal.cling.registry.Registry").setLevel(Level.FINER);
        Logger.getLogger("org.teleal.cling.registry.LocalItems").setLevel(Level.FINER);
        Logger.getLogger("org.teleal.cling.registry.RemoteItems").setLevel(Level.FINER);
	}

}
